#ifndef TARSTHREADPOOL_H
#define TARSTHREADPOOL_H
#include <iostream>
#include <future>
#include <queue>
#include <vector>
#include <functional>
using namespace std;
///////////由时间管理类管理//////////////
void getNow(timeval *tv);
uint64_t getNowMs();
#define TNOW    getNow()
#define TNOWMS  getNowMs()
/////////////////////////////////////////////////
#define THREAD_MAX_NUM      5 // 线程最大数量
/**
 * @file TarsThreadPool.h
 * @brief 线程池类,采用c++11来实现了 (一个非常简单的实现)
 * 使用说明:
 * TC_ThreadPool tpool;
 * tpool.init(5);   //初始化线程池线程数
 * //启动线程方式
 * tpool.start();
 * //将任务丢到线程池中
 * tpool.exec(testFunction, 10);    //参数和start相同
 * //等待线程池结束
 * tpool.waitForAllDone(1000);      //参数<0时, 表示无限等待(注意有人调用stop也会推出)
 * //此时: 外部需要结束线程池是调用
 * tpool.stop();
 * 注意:
 * TC_ThreadPool::exec执行任务返回的是个future, 因此可以通过future异步获取结果, 比如:
 * int testInt(int i)
 * {
 *     return i;
 * }
 * auto f = tpool.exec(testInt, 5);
 * cout << f.get() << endl;   //当testInt在线程池中执行后, f.get()会返回数值5
 *
 * class Test
 * {
 * public:
 *     int test(int i);
 * };
 * Test t;
 * auto f = tpool.exec(std::bind(&Test::test, &t, std::placeholders::_1), 10);
 * //返回的future对象, 可以检查是否执行
 * cout << f.get() << endl;
 * @note  基于腾讯开源项目Tars里的线程池实现
 */
/////////////////////////////////////////////////
class TarsThreadPool
{
protected:
    struct TaskFunc
    {
        TaskFunc(uint64_t expireTime) : _expireTime(expireTime)
        { }

        function<void()>        _func;              //线程执行的任务
        uint64_t                _expireTime = 0;	//超时的绝对时间
    };
    using TaskFuncPtr = shared_ptr<TaskFunc>;       //重命名

//单例模式
public:
    /**
     * @brief 析构, 会停止所有线程
     */
    virtual ~TarsThreadPool();
    TarsThreadPool(const TarsThreadPool&)=delete;
    TarsThreadPool& operator=(const TarsThreadPool&)=delete;
    TarsThreadPool(const TarsThreadPool&&)=delete;
    TarsThreadPool& operator=(const TarsThreadPool&&)=delete;
    /**
     * @brief 获取唯一实例类
     */
    static TarsThreadPool& getInstance();

private:
    /**
     * @brief 构造函数
     */
    TarsThreadPool();

public:
    /**
     * @brief 初始化
     * @param num: 工作线程个数
     * @return true: 成功 false: 失败
     */
    bool init(size_t num);
    /**
     * @brief 获取线程个数
     */
    size_t getThreadNum();
    /**
     * @brief 获取当前线程池的任务数
     */
    size_t getJobNum();
    /**
     * @brief 停止所有线程, 会等待所有线程结束
     */
    void stop();
    /**
     * @brief 启动所有线程
     * @return true: 成功 false: 失败
     */
    bool start();
    /**
     * @brief 用线程池启用任务(F是function, Args是参数)
     * @param f: 任务函数
     * @param args: 函数的参数
     * @return 返回任务的future对象, 可以通过f这个对象来获取返回值
     */
    template <class F, class... Args>
    auto exec(F&& f, Args&&... args) -> future<decltype(f(args...))>
    {
        return exec(0, f, args...);
    }
    /**
     * @brief 用线程池启用任务(F是function, Args是参数)
     * @param timeoutMs: 超时时间 ，单位ms (为0时不做超时控制) ；若任务超时，此任务将被丢弃
     * @param f: 任务函数
     * @param args: 函数的参数
     * @return 返回任务的future对象, 可以通过这个对象来获取返回值
     */
    template <class F, class... Args>   // 使用了返回值后置语法 类似与java的反射原理
    auto exec(int64_t timeoutMs, F&& f, Args&&... args) -> std::future<decltype(f(args...))>
    {
        // 获取超时时间
        int64_t expireTime =  (timeoutMs == 0 ? 0 : TNOWMS + timeoutMs);
        // 定义返回值类型 类型推到的方式
        using RetType = decltype(f(args...));
        // 封装任务包 使用智能指针保存
        auto task = make_shared<packaged_task<RetType()>>(bind(forward<F>(f), forward<Args>(args)...));
        // 封装任务指针，设置过期时间
        TaskFuncPtr fPtr = std::make_shared<TaskFunc>(expireTime);
        fPtr->_func = [task]() { // 保存任务 智能指针使用值传递
            (*task)();
        };

        unique_lock<mutex> lock(_mutex);
        // 将任务对象插入队列
        _tasks.push(fPtr);
        // 唤醒其中一个空闲线程去执行任务
        _condition.notify_one();
        // 返回future对象, 可以通过这个对象来获取返回值
        return task->get_future();
    }
    /**
     * @brief 等待当前任务队列中, 所有task全部结束(队列无任务).
     * @param millsecond 等待的时间(ms), -1:永远等待
     * @return           true, 所有工作都处理完毕
     *                   false,超时退出
     */
    bool waitForAllDone(int millsecond = -1);
    /**
     * @brief 线程池是否退出
     */
    bool isTerminate() { return _bTerminate; }

protected:
    /**
     * @brief 获取任务
     */
    bool get(TaskFuncPtr& task);
    /**
     * @brief 执行任务的线程
     */
    void run();

protected:
    queue<TaskFuncPtr>  _tasks;     //任务队列
    vector<thread*>     _threads;   //工作线程
    mutex               _mutex;     //线程池内部锁
    condition_variable  _condition; //线程池内部信号量
    size_t              _threadNum; //线程池内线程数量
    bool                _bTerminate;//线程池退出标志
    atomic_int          _atomic;    //工作线程计数器
};

#endif // TARSTHREADPOOL_H
